﻿using System;
using System.ComponentModel;
using System.Net;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using LIK.NetworkTools;

namespace LIK.WakeOnLan
{

    public static class ArpRequest
    {
        /// <summary>
        /// Sends a request via the ARP protocol to resolve IP address into the physical address. 
        /// If it is already in the cache of this host, willl be returned chached address.
        /// </summary>
        /// <param name="destination"></param>
        /// <returns>Eine <see cref="T:System.Net.ArpRequestResult"></see></returns>
        public static ArpRequestResult Send(IPAddress destination)
        {
            if (destination == null)
                throw new ArgumentNullException("destination");

            int destIp = BitConverter.ToInt32(destination.GetAddressBytes(), 0);

            var addr = new byte[6];
            var len = addr.Length;

            var res = NativeMethods.SendARP(destIp, 0, addr, ref len);

            if (res == 0)
                return new ArpRequestResult(new PhysicalAddress(addr));
            return new ArpRequestResult(new Win32Exception(res));
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="destination">Die Ziel-IPAdress</param>
        /// <returns>Ein asynchroner Task, welcher einen ARP-Request sendet.</returns>
        public static Task<ArpRequestResult> SendAsync(IPAddress destination)
        {
            return Task.Run(() => Send(destination));
        }
    }



    public class ArpRequestResult
    {
        public Exception Exception { get; private set; }

        public PhysicalAddress Address { get; private set; }

        public ArpRequestResult(PhysicalAddress address)
        {
            Exception = null;
            Address = address;
        }

        public ArpRequestResult(Exception exception)
        {
            Exception = exception;
            Address = null;
        }

        public override string ToString()
        {
            var sb = new StringBuilder();
            if (Address == null)
                sb.Append("no address");
            else
            {
                sb.Append("address: ");
                sb.Append(Address);
            }
            sb.Append(", ");
            if (Exception == null)
                sb.Append("no exception");
            else
            {
                sb.Append("exception: ");
                sb.Append(Exception.Message);
            }
            return sb.ToString();
        }
    }

}
